package org.act.BPEL2Automata.graphics.model;

import java.awt.Point;
import java.util.LinkedList;

/**
 * This class used to draw automata.It contains states and transitions.
 * 
 * @author baoxiwu<bb@feijiao.info>,ACT,Beihang University
 * @version 0.9.0
 * @since 2010-05-16
 * 
 */
public class Automaton{
	public static final int ADJUST_TYPE_HORIZONTAL_LEFT = -2;
	public static final int ADJUST_TYPE_HORIZONTAL_RIGHT = -1;
	public static final int ADJUST_TYPE_VERTICAL_UP = 0;
	public static final int ADJUST_TYPE_VERTICAL_DOWN = 1;
	public static final int ADJUST_TYPE_REVERSE = 2;
	public static final int ADJUST_SPACING = 65;
	
	private LinkedList<State4G> stateSet = new LinkedList<State4G>();
	private LinkedList<TransitionRule> transitionRuleSet = new LinkedList<TransitionRule>();
	
	
	public LinkedList<TransitionRule> getTransitionRuleSet() {
		return transitionRuleSet;
	}

	public void setTransitionRuleSet(LinkedList<TransitionRule> transitionRuleSet) {
		this.transitionRuleSet = transitionRuleSet;
	}

	public void addTransitionRule(TransitionRule tr){
		this.transitionRuleSet.add(tr);
	}
	
	public void addTransitionRule(LinkedList<TransitionRule> trs){
		this.transitionRuleSet.addAll(trs);
	}
	
	public void setStateSet(LinkedList<State4G> stateSet) {
		this.stateSet = stateSet;
	}

	public LinkedList<State4G> getStateSet(){
		return this.stateSet;		
	}
	
	public void addState(State4G state){
		this.stateSet.add(state);
	}
	
	public void addState(LinkedList<State4G> states){
		this.stateSet.addAll(states);
	}
	
	
	public void adjust(int type,int offset){
		if(type == Automaton.ADJUST_TYPE_HORIZONTAL_RIGHT){
			for(int i = 0; i < this.getStateSet().size(); i++){
				Point point = new Point(this.getStateSet().get(i).getPoint().x + offset
						,this.getStateSet().get(i).getPoint().y);
				
				this.getStateSet().get(i).setPoint(point);
			}
		}
		else
		if(type == Automaton.ADJUST_TYPE_REVERSE){
			if(this.isPlainSequence()){
				return;
			}
			
			int central = this.getCentralY();
			
			for(int i = 0; i < this.getStateSet().size(); i++){
				Point point = new Point(this.getStateSet().get(i).getPoint().x
						,2* central - this.getStateSet().get(i).getPoint().y);
				
				this.getStateSet().get(i).setPoint(point);
			}
		}
	}
	
	
	private boolean isPlainSequence(){
		int min = Integer.MAX_VALUE,max = 0;
		State4G minS = null,maxS = null;
		
		for(int i = 0; i < this.getStateSet().size(); i++){
			if(this.getStateSet().get(i).getPoint().getY() < min){
				min = this.getStateSet().get(i).getPoint().x;
				minS = this.getStateSet().get(i);
			}
			
			if(this.getStateSet().get(i).getPoint().getY() > max){
				max = this.getStateSet().get(i).getPoint().x;
				maxS = this.getStateSet().get(i);
			}
		}
		
		if(Integer.parseInt(maxS.getFrom().getID()) > Integer.parseInt(minS.getFrom().getID())){
			return true;
		}
		else{
			return false;
		}
	}
	
	public int getXSpan(){
		int min = Integer.MAX_VALUE,max = 0;
		
		for(int i = 0; i < this.getStateSet().size(); i++){
			if(this.getStateSet().get(i).getPoint().getX() < min){
				min = this.getStateSet().get(i).getPoint().x;
			}
			
			if(this.getStateSet().get(i).getPoint().getX() > max){
				max = this.getStateSet().get(i).getPoint().x;
			}
		}
		
		return (max - min);
	}
	
	private int getCentralY(){
		int min = Integer.MAX_VALUE,max = 0;
		
		for(int i = 0; i < this.getStateSet().size(); i++){
			if(this.getStateSet().get(i).getPoint().getY() < min){
				min = this.getStateSet().get(i).getPoint().y;
			}
			
			if(this.getStateSet().get(i).getPoint().getY() > max){
				max = this.getStateSet().get(i).getPoint().y;
			}
		}
		
		return (int)((max + min)/2);
	}
	
	
	public String toString(){
		String result = "DECRIPTION OF AUTOMATON\nState:\n";
		
		for(int i = 0; i < this.stateSet.size(); i++){
			result += ("s" +  this.getStateSet().get(i).getID() 
					+ " type=" + (this.getStateSet().get(i).getType() == State4G.STATE4G_TYPE_OTHER ? 
							"OTHER" :(this.getStateSet().get(i).getType() == State4G.STATE4G_TYPE_START ? 
									"START" : "FINAL"))
					+ " from=s" + this.getStateSet().get(i).getFrom().getID()
					+ " D(" + this.stateSet.get(i).getPoint().getX()
					+ "," 
					+ this.stateSet.get(i).getPoint().getY()+ ")\n");
		}
		
		result += "\nTransition Rule:\n";
		
		for(int i = 0; i < this.transitionRuleSet.size(); i++){
			result += "s" + this.transitionRuleSet.get(i).getStartState().getID()
				+ "_mes" + this.transitionRuleSet.get(i).getMessage().getID()
				+ "->s" + this.transitionRuleSet.get(i).getEndState().getID()
				+"\n";
		}
		
		return result;
	}
}